1 using System;
2 using
System.Collections.Generic;
3 using
UnityEngine;
4 using
UnityEngine.Assertions;
5
6 namespace
ProceduralToolkit.Examples
7 {
8     
public static class RoofGenerator
9     {
10         
private const float GabledRoofHeight = 2;
11         
private const float HippedRoofHeight = 2;
12
13         
public static MeshDraft Generate(
14             List<Vector2> foundationPolygon,
15             
float roofHeight,
16             RoofConfig roofConfig)
17         {
18             List<Vector2> roofPolygon = OffsetPolygon(foundationPolygon, -roofConfig.overhang);
19
20             MeshDraft roofDraft;
21             
switch (roofConfig.type)
22             {
23                 
case RoofType.Flat:
24                     roofDraft = GenerateFlat(roofPolygon, roofConfig);
25                     
break;
26                 
case RoofType.Gabled:
27                     roofDraft = GenerateGabled(roofPolygon, roofConfig);
28                     
break;
29                 
case RoofType.Hipped:
30                     roofDraft = GenerateHipped(roofPolygon, roofConfig);
31                     
break;
32                 
default:
33                     
throw new ArgumentOutOfRangeException();
34             }
35
36             
if (roofConfig.thickness > 0)
37             {
38                 roofDraft.Add(GenerateBorder(roofPolygon, roofConfig));
39             }
40
41             
if (roofConfig.overhang > 0)
42             {
43                 roofDraft.Add(GenerateOverhang(foundationPolygon, roofPolygon));
44             }
45
46             roofDraft.Move(Vector3.up*roofHeight);
47             roofDraft.uv.Clear();
48             
return roofDraft;
49         }
50
51         
private static MeshDraft GenerateFlat(List<Vector2> roofPolygon, RoofConfig roofConfig)
52         {
53             Vector3 a = roofPolygon[
0].ToVector3XZ() + Vector3.up*roofConfig.thickness;
54             Vector3 b = roofPolygon[
1].ToVector3XZ() + Vector3.up*roofConfig.thickness;
55             Vector3 c = roofPolygon[
2].ToVector3XZ() + Vector3.up*roofConfig.thickness;
56             Vector3 d = roofPolygon[
3].ToVector3XZ() + Vector3.up*roofConfig.thickness;
57
58             
var roofDraft = MeshDraft.Quad(a, d, c, b);
59             
return roofDraft;
60         }
61
62         
public static MeshDraft GenerateGabled(List<Vector2> roofPolygon, RoofConfig roofConfig)
63         {
64             Vector3 a = roofPolygon[
0].ToVector3XZ() + Vector3.up*roofConfig.thickness;
65             Vector3 b = roofPolygon[
1].ToVector3XZ() + Vector3.up*roofConfig.thickness;
66             Vector3 c = roofPolygon[
2].ToVector3XZ() + Vector3.up*roofConfig.thickness;
67             Vector3 d = roofPolygon[
3].ToVector3XZ() + Vector3.up*roofConfig.thickness;
68
69             Vector3 ridgeHeight = Vector3.up*GabledRoofHeight;
70             Vector3 ridge0 = (a + d)/
2 + ridgeHeight;
71             Vector3 ridge1 = (b + c)/
2 + ridgeHeight;
72
73             
var roofDraft = MeshDraft.Quad(a, ridge0, ridge1, b);
74             roofDraft.Add(MeshDraft.Triangle(b, ridge1, c));
75             roofDraft.Add(MeshDraft.Quad(c, ridge1, ridge0, d));
76             roofDraft.Add(MeshDraft.Triangle(d, ridge0, a));
77             
return roofDraft;
78         }
79
80         
public static MeshDraft GenerateHipped(List<Vector2> roofPolygon, RoofConfig roofConfig)
81         {
82             Vector3 a = roofPolygon[
0].ToVector3XZ() + Vector3.up*roofConfig.thickness;
83             Vector3 b = roofPolygon[
1].ToVector3XZ() + Vector3.up*roofConfig.thickness;
84             Vector3 c = roofPolygon[
2].ToVector3XZ() + Vector3.up*roofConfig.thickness;
85             Vector3 d = roofPolygon[
3].ToVector3XZ() + Vector3.up*roofConfig.thickness;
86
87             Vector3 ridgeHeight = Vector3.up*HippedRoofHeight;
88             Vector3 ridgeOffset = (b - a).normalized*
2;
89             Vector3 ridge0 = (a + d)/
2 + ridgeHeight + ridgeOffset;
90             Vector3 ridge1 = (b + c)/
2 + ridgeHeight - ridgeOffset;
91             
var roofDraft = MeshDraft.Quad(a, ridge0, ridge1, b);
92             roofDraft.Add(MeshDraft.Triangle(b, ridge1, c));
93             roofDraft.Add(MeshDraft.Quad(c, ridge1, ridge0, d));
94             roofDraft.Add(MeshDraft.Triangle(d, ridge0, a));
95             
return roofDraft;
96         }
97
98         
private static MeshDraft GenerateBorder(List<Vector2> roofPolygon, RoofConfig roofConfig)
99         {
100             List<Vector3> lowerRing = roofPolygon.ConvertAll(v => v.ToVector3XZ());
101             List<Vector3> upperRing = roofPolygon.ConvertAll(v => v.ToVector3XZ() + Vector3.up*roofConfig.thickness);
102             
var border = MeshDraft.FlatBand(lowerRing, upperRing);
103             
return border;
104         }
105
106         
private static MeshDraft GenerateOverhang(List<Vector2> foundationPolygon, List<Vector2> roofPolygon)
107         {
108             List<Vector3> lowerRing = foundationPolygon.ConvertAll(v => v.ToVector3XZ());
109             List<Vector3> upperRing = roofPolygon.ConvertAll(v => v.ToVector3XZ());
110             
var overhang = MeshDraft.FlatBand(lowerRing, upperRing);
111             
return overhang;
112         }
113
114         
private static List<Vector2> OffsetPolygon(List<Vector2> polygon, float distance)
115         {
116             
var newPolygon = new List<Vector2>();
117             
for (int i = 0; i < polygon.Count; i++)
118             {
119                 
var previous = polygon.GetLooped(i - 1);
120                 
var current = polygon[i];
121                 
var next = polygon.GetLooped(i + 1);
122                 
float angle;
123                 Vector2 bisector = GetBisector(previous, current, next,
out angle);
124                 
float hypotenuse = distance/GetBisectorSin(angle);
125
126                 newPolygon.Add(current + bisector*hypotenuse);
127             }
128             
return newPolygon;
129         }
130
131         
private static Vector2 GetBisector(Vector2 previous, Vector2 current, Vector2 next, out float angle)
132         {
133             Vector2 toPrevious = (previous - current).normalized;
134             Vector2 toNext = (next - current).normalized;
135
136             angle = PTUtils.Angle360(toPrevious, toNext);
137             Assert.IsFalse(
float.IsNaN(angle));
138             
return toPrevious.RotateCW(angle/2);
139         }
140
141         
private static float GetBisectorSin(float angle)
142         {
143             
if (angle > 180)
144             {
145                 angle =
360 - angle;
146             }
147             
return Mathf.Sin(angle/2*Mathf.Deg2Rad);
148         }
149     }
150
151     
public enum RoofType
152     {
153         Flat,
154         Hipped,
155         Gabled,
156     }
157
158     
[Serializable]
159     
public class RoofConfig
160     {
161         
public RoofType type = RoofType.Flat;
162         
public float thickness;
163         
public float overhang;
164     }
165 }


Gõ tìm kiếm nhanh...